package com.peoit.honeycomb.application.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;

import javax.transaction.Transactional;

import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.peoit.honeycomb.application.ProjectApplication;
import com.peoit.honeycomb.domain.Accessory;
import com.peoit.honeycomb.domain.HoneycombProject;
import com.peoit.honeycomb.domain.Investment;
import com.peoit.honeycomb.domain.User;
import com.peoit.honeycomb.domain.exception.AmountExcessiveException;
import com.peoit.honeycomb.domain.exception.ProjectNotExistException;
import com.peoit.honeycomb.domain.exception.ProjectNotInInvestStatus;
import com.peoit.honeycomb.domain.exception.UserNotExistException;
import com.peoit.honeycomb.domain.repository.HibernateEntityRepository;
import com.peoit.honeycomb.dto.Config;
import com.peoit.honeycomb.dto.InvestmentDto;
import com.peoit.honeycomb.dto.ProjectQueryDto;
import com.peoit.honeycomb.util.CommonUtil;

/**
 * Created by Bing.Zeng on 2015/9/26.
 */
@Service
public class ProjectApplicationImpl extends HibernateEntityRepository implements ProjectApplication {
	Logger logger = Logger.getLogger(ProjectApplicationImpl.class.getName());

	/**
	 * 验证审核项目
	 *
	 * @param projectId
	 * @param passOrNot
	 * @return
	 */
	@Override
	@Transactional
	public boolean verify(String projectId, boolean passOrNot) {
		HoneycombProject project = find(HoneycombProject.class, projectId);

		if (project == null) {
			throw new ProjectNotExistException();
		}
		// 验证当前状态
		if (Config.waitingVerified.equals(project.getStatus())) {
			if (passOrNot) {
				project.setStatus(Config.waitingPay);
			} else {
				project.setStatus(Config.verifyFailed);
			}
			update(project);
		} else {
			throw new IllegalStateException();
		}
		return true;
	}

	/**
	 * 是否同意延期
	 *
	 * @param projectId
	 * @param passOrNot
	 * @return
	 */
	@Transactional
	public boolean postpone(String projectId, boolean passOrNot) {
		HoneycombProject project = find(HoneycombProject.class, projectId);

		if (project == null) {
			throw new ProjectNotExistException();
		}
		// 验证当前状态
		if (Config.investDelay.equals(project.getStatus())) {
			if (passOrNot) {
				project.setStatus(Config.waitingInvested);
			} else {
				project.setStatus(Config.projectFailed);
			}
			update(project);
		} else {
			throw new IllegalStateException();
		}
		return true;
	}

	/**
	 * 根据条件分页查询 project
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public List<HoneycombProject> findByWherePage(ProjectQueryDto dto) throws ParseException {

		int pageSize = dto.getPageSize();
		int offset = dto.getOffset();

		List<Object> parameters = new ArrayList<>();

		StringBuffer where = new StringBuffer("");
		if (!StringUtils.isEmpty(dto.getCity())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" projectCity like  ? ");
			parameters.add("%" + dto.getCity() + "%");
		}

		if (!StringUtils.isEmpty(dto.getProjectName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" projectName like ? ");
			parameters.add("%" + dto.getProjectName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getStatus())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" status = ? ");
			parameters.add(dto.getStatus());
		}

		if (!StringUtils.isEmpty(dto.getPublisherId())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" publisher.id = ? ");
			parameters.add(dto.getPublisherId());
		}
		if (!StringUtils.isEmpty(dto.getIndustryType())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" industryType = ? ");
			parameters.add(dto.getIndustryType());
		}
		if (!StringUtils.isEmpty(dto.getProjectType())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" projectType = ? ");
			parameters.add(dto.getProjectType());
		}
		if (!StringUtils.isEmpty(dto.getProjectId())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" id = ? ");
			parameters.add(dto.getProjectId());
		}
		if (!StringUtils.isEmpty(dto.getSortByEndTime())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" endDate <= ? ");
			parameters.add(new SimpleDateFormat("yyyy-MM-dd").parse(dto.getSortByEndTime().toString()));
		}
		if (!StringUtils.isEmpty(dto.getStatusMark())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" status = ? or status = ? ");
			parameters.add(Config.projectSuccess);
			parameters.add(Config.waitingInvested);
		}

		Object[] os = CommonUtil.listToArray(parameters);
		List<HoneycombProject> tmpResult = queryByWherePage(HoneycombProject.class, where.toString(), os, offset,
				pageSize);
		List<HoneycombProject> result = new ArrayList<HoneycombProject>();
		if (!StringUtils.isEmpty(dto.getAmountPercent())) {
			for (HoneycombProject project : tmpResult) {
				if (project.getInvestedAmount() >= project.getSellStockMoney()
						* Double.parseDouble(dto.getAmountPercent())) {
					result.add(project);
				}
			}
		} else {
			result = tmpResult;
		}
		if (!StringUtils.isEmpty(dto.getTopSellStockMoney())) {
			Collections.sort(result, new Comparator<HoneycombProject>() {
				@Override
				public int compare(HoneycombProject project1, HoneycombProject project2) {
					return (Long.valueOf(String.valueOf(project1.getInvestedAmount()).replace(".", "")))
							.compareTo(Long.valueOf(String.valueOf(project2.getInvestedAmount()).replace(".", "")));
				}
			});
			HoneycombProject tmpProject = result.get(0);
			result = new ArrayList<HoneycombProject>();
			result.add(tmpProject);

		}
		return result;

	}

	/**
	 * 根据条件返回 总条数
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public long findByWhereCount(ProjectQueryDto dto) {

		List<Object> parameters = new ArrayList<>();

		StringBuffer where = new StringBuffer("");
		if (!StringUtils.isEmpty(dto.getCity())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" projectCity like  ? ");
			parameters.add("%" + dto.getCity() + "%");
		}

		if (!StringUtils.isEmpty(dto.getProjectName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" projectName like ? ");
			parameters.add("%" + dto.getProjectName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getStatus())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" status = ? ");
			parameters.add(dto.getStatus());
		}
		long result;
		if (StringUtils.isEmpty(where.toString())) {
			result = getCountByWhere(HoneycombProject.class);

		} else {
			result = getCountByWhere(HoneycombProject.class, where.toString(), CommonUtil.listToArray(parameters));
		}
		return result;
	}

	/**
	 * 发布项目
	 *
	 * @param honeycombProject
	 */
	@Override
	@Transactional
	public HoneycombProject create(String userId, HoneycombProject honeycombProject) {

		User publisher = find(User.class, userId);

		if (publisher == null) {
			throw new UserNotExistException();
		}

		honeycombProject.setPublisher(publisher);
		honeycombProject = create(honeycombProject);
		for (Accessory accessory : honeycombProject.getAccessories()) {
			create(accessory);
		}

		return honeycombProject;

	}

	/**
	 * 修改项目
	 *
	 * @param UserId
	 * @param honeycombProject
	 * @return
	 */
	@Transactional
	public HoneycombProject updateProject(String UserId, HoneycombProject honeycombProject) {
		User publisher = find(User.class, UserId);

		if (publisher == null) {
			throw new UserNotExistException();
		}

		honeycombProject.setPublisher(publisher);

		StringBuffer jpql = new StringBuffer("delete from Accessory a where a.project.id = ?");
		Object[] params = { honeycombProject.getId() };
		updateByFullJPQL(jpql.toString(), params);

		for (Accessory accessory : honeycombProject.getAccessories()) {
			create(accessory);
		}
		// 修改项目
		update(honeycombProject);

		return honeycombProject;
	}

	/**
	 * 取消关注或者关注项目
	 *
	 * @param userId
	 * @param projectId
	 * @param concern
	 *            y/n
	 * @return
	 */
	@Override
	@Transactional
	public boolean concern(String userId, String projectId, String concern) {
		User user = find(User.class, userId);

		if (user == null) {
			throw new UserNotExistException();
		}

		HoneycombProject project = find(HoneycombProject.class, projectId);

		if (project == null) {
			throw new ProjectNotExistException();
		}
		if ("y".equalsIgnoreCase(concern)) {
			project.getObservers().add(user);

		} else if ("n".equalsIgnoreCase(concern)) {
			project.getObservers().remove(user);
		} else {
			throw new IllegalStateException("concern should be y or n");
		}

		update(project);

		return true;
	}

	/**
	 * 用户是否关注了指定项目
	 *
	 * @param userId
	 * @param projectId
	 * @return
	 */
	@Override

	public boolean isConcern(String userId, String projectId) {
		User user = find(User.class, userId);

		if (user == null) {
			throw new UserNotExistException();
		}

		HoneycombProject project = find(HoneycombProject.class, projectId);

		if (project == null) {
			throw new ProjectNotExistException();
		}

		Object[] parameters = { userId, projectId };

		StringBuffer jpql = new StringBuffer(
				"SELECT p FROM HoneycombProject p  LEFT JOIN p.observers o WHERE o.id =? AND p.id = ?");

		List<HoneycombProject> projects = queryByFullJPQL(jpql.toString(), parameters);

		return projects != null && projects.size() > 0;

	}

	/**
	 * 分页查询关注项目
	 *
	 * @param userId
	 * @return
	 */

	public List<HoneycombProject> findConcernedProjectPage(String userId, int offset, int pageSize) {
		User user = find(User.class, userId);

		if (user == null) {
			throw new UserNotExistException();
		}

		Object[] parameters = { userId };

		StringBuffer jpql = new StringBuffer(
				"SELECT distinct p FROM HoneycombProject p  LEFT JOIN p.observers o WHERE o.id =?");

		List<HoneycombProject> projects = queryByFullJPQLPage(jpql.toString(), parameters, offset, pageSize);

		return projects;

	}

	/**
	 * 投资项目
	 *
	 * @param dto
	 * @return
	 */
	@Override
	@Transactional
	public boolean invest(InvestmentDto dto) {
		User user = find(User.class, dto.getUserId());

		if (user == null) {
			throw new UserNotExistException();
		}

		HoneycombProject project = find(HoneycombProject.class, dto.getProjectId());

		if (project == null) {
			throw new ProjectNotExistException();
		}

		// 校验项目状态，是否可投，可投金额等
		if (!project.getStatus().toString().equals(Config.waitingInvested)) {
			throw new ProjectNotInInvestStatus();
		}
		if (project.getAvailableAmount() < dto.getAmount()) {
			throw new AmountExcessiveException();
		}
		// TODO 如果达到项目启动状态，像用户发送信息
		Investment investment = new Investment();
		investment.setUser(user);
		investment.setProject(project);
		investment.setAmount(dto.getAmount());
		investment.setDescription(dto.getDescription());
		investment.setStatus(1);
		project.getInvestments().add(investment);

		create(investment);
		update(project);

		return true;
	}

	/**
	 * 分页查询已投资的项目
	 *
	 * @param userId
	 * @param offset
	 * @param pageSize
	 * @return
	 */
	@Override
	public List<HoneycombProject> findInvesteddProject(String userId, int offset, int pageSize) {
		User user = find(User.class, userId);

		if (user == null) {
			throw new UserNotExistException();
		}

		Object[] parameters = { userId };

		StringBuffer jpql = new StringBuffer(
				"SELECT distinct p FROM HoneycombProject p  LEFT JOIN p.investments i WHERE i.user.id =?");

		List<HoneycombProject> projects = queryByFullJPQLPage(jpql.toString(), parameters, offset, pageSize);

		return projects;
	}

	/**
	 * 分页查询已投资的项目，且该项目已成功
	 *
	 * @param userId
	 * @param offset
	 * @param pageSize
	 * @return
	 */
	@Override
	public List<HoneycombProject> findInvesteddSuccessProject(String userId, int offset, int pageSize) {
		User user = find(User.class, userId);

		if (user == null) {
			throw new UserNotExistException();
		}

		Object[] parameters = { userId, Config.projectSuccess };

		StringBuffer jpql = new StringBuffer(
				"SELECT distinct p FROM HoneycombProject p  LEFT JOIN p.investments i WHERE i.user.id =? and p.status = ? ");
		List<HoneycombProject> projects = queryByFullJPQLPage(jpql.toString(), parameters, offset, pageSize);

		return projects;
	}

	/**
	 * 支付项目保证金
	 *
	 * @param projectId
	 * @return
	 */
	@Transactional
	public Boolean payMargin(String projectId) {
		HoneycombProject project = find(HoneycombProject.class, projectId);
		project.setStatus(Config.waitingInvested);
		update(project);
		return true;
	}

	/**
	 * 启动项目
	 *
	 * @param dto
	 */
	@Transactional
	public void startProject(ProjectQueryDto dto) {
		HoneycombProject project = find(HoneycombProject.class, dto.getId());
		if (project == null) {
			throw new ProjectNotExistException();
		}
		project.setStatus(Config.projectSuccess);
	}

	/**
	 * 终止项目
	 *
	 * @param dto
	 */
	@Transactional
	public void stopProject(ProjectQueryDto dto) {
		HoneycombProject project = find(HoneycombProject.class, dto.getId());
		if (project == null) {
			throw new ProjectNotExistException();
		}
		project.setStatus(Config.projectEnd);
	}

	/**
	 * 变更投资状态
	 *
	 * @param dto
	 */
	@Transactional
	public void changeInvestStatus(String id, int status) {
		Investment investment = find(Investment.class, id);
		investment.setStatus(status);
	}

	/**
	 * 取消项目
	 *
	 * @param dto
	 */
	@Transactional
	public void cancelProject(ProjectQueryDto dto) {
		HoneycombProject project = find(HoneycombProject.class, dto.getId());
		if (project == null) {
			throw new ProjectNotExistException();
		}
		project.setCancelRemarks(dto.getCancelRemarks());
		project.setStatus(Config.projectCancel);
	}

	/**
	 * 设置保证金
	 */
	@Override
	@Transactional
	public void updateEarnestPercent(String projectId, double projectEarnestPercent, double investorEarnestPercent) {
		HoneycombProject project = find(HoneycombProject.class, projectId);
		project.setProjectEarnestPercent(projectEarnestPercent / 100);
		project.setInvestorEarnestPercent(investorEarnestPercent / 100);
		update(project);
	}

	@Override
	@Transactional
	public void cancelInvest(String projectId, String investId) {
		HoneycombProject project = find(HoneycombProject.class, projectId);
		if (project == null) {
			throw new ProjectNotExistException();
		}
		User user = find(User.class, investId);
		if (user == null) {
			throw new UserNotExistException();
		}
		String sql = "update Investment i set status = ? where i.project.id = ? and i.user.id = ?";
		Object[] params = { 3, projectId, investId };
		updateByFullJPQL(sql, params);
	}

	@Override
	@Transactional
	public void applyDelay(ProjectQueryDto dto) {
		HoneycombProject project = find(HoneycombProject.class, dto.getProjectId());
		if (project == null) {
			throw new ProjectNotExistException();
		}
		project.setStatus(Config.delayVerify);
		project.setDelayremarks(dto.getDelayRemarks());
		update(project);
	}
}
